// Learn TypeScript:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/typescript.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/life-cycle-callbacks.html

const { ccclass, property } = cc._decorator;

@ccclass
export default class Bezier {


    // 曲线点集合,曲线总长,上一个点,当前时间
    private _pointLists;
    private totalLength
    private prevPos
    private currentRunTime;
    // 运行时间
    private _runTime = 0;
    private _pointArr = [];

    constructor(pointArr, allTime = 2) {
        this._runTime = allTime;
        this._pointArr = pointArr
    }

    // 重置数据
    resetData() {
        // 点集合
        this._pointLists = [];
        // 线段总长度
        this.totalLength = this.currentRunTime = 0;
        // 初始位置
        this.prevPos = {
            x: this._pointArr[0].x,
            y: this._pointArr[0].y,
            length: 0,
        }
    }

    //阶乘
    factorial(i) {
        let n = 1;
        for (let j = 1; j <= i; j++)
            n *= j;
        return n;
    }
    // ------------------------【核心代码】---------------------------
    ComputeBezier(dt, runTime) {
        // 把时间从 [0,runTime] 映射到 [0,1] 之间
        let t = this.currentRunTime / runTime;

        var x = 0, y = 0;
        //控制点数组
        var n = this._pointArr.length - 1;

        this._pointArr.forEach((item, index) => {
            if (!index) {
                x += item.x * Math.pow((1 - t), n - index) * Math.pow(t, index)
                y += item.y * Math.pow((1 - t), n - index) * Math.pow(t, index)
            } else {
                //factorial为阶乘函数
                x += this.factorial(n) / this.factorial(index) / this.factorial(n - index) * item.x * Math.pow((1 - t), n - index) * Math.pow(t, index)
                y += this.factorial(n) / this.factorial(index) / this.factorial(n - index) * item.y * Math.pow((1 - t), n - index) * Math.pow(t, index)
            }
        })

        //  // 二阶贝塞尔曲线公式 (t => [0,1]) 
        //  var x = Math.pow(1 - t, 2) * _startPos.x
        //  + 2 * t * (1 - t) * _controlPos.x
        //  + Math.pow(t, 2) * _endPos.x;

        //  var y = Math.pow(1 - t, 2) * _startPos.y
        //  + 2 * t * (1 - t) * _controlPos.y
        //  + Math.pow(t, 2) * _endPos.y;

        // console.log(`x:${x},y:${y}`);
        // 计算两点距离
        let length = Math.sqrt(Math.pow(this.prevPos.x - x, 2) + Math.pow(this.prevPos.y - y, 2));
        let v2 = { x, y, length };
        // 存储当前节点
        this._pointLists.push(v2);
        this.prevPos = v2;
        // 累计长度
        this.totalLength += length;
        // 累计时间
        this.currentRunTime += dt;

    }

    // 切割贝塞尔曲线
    getPoints(count = 200) {
        this.resetData();
        // 分割时间
        let dt = this._runTime / count;
        // 开始分割曲线
        for (var i = 0, len = count + 1; i < len; i++) {
            this.ComputeBezier(dt, this._runTime);
        }
        return this._pointLists
    }

    getCurveLength() {
        return this.totalLength;
    }
}
